#include "RS485_Wind_Direction_Transmitter_V2.h"


RS485_Wind_Direction_Transmitter_V2::RS485_Wind_Direction_Transmitter_V2()
{
    _hardSerial = NULL;
    _softSerial = NULL;

}

RS485_Wind_Direction_Transmitter_V2::~RS485_Wind_Direction_Transmitter_V2()
{


}

void RS485_Wind_Direction_Transmitter_V2::begin(HardwareSerial &myhardSerial)
{
    serialMode = 0;
    _hardSerial = &myhardSerial;

}

void RS485_Wind_Direction_Transmitter_V2::begin(SoftwareSerial &mysoftSerial)
{
    serialMode = 1;
    _softSerial = &mysoftSerial;

}

uint8_t RS485_Wind_Direction_Transmitter_V2::GetWindDirection(uint8_t Address)
{
  uint8_t data[2] = {0};
  readHoldingRegister(0, 0x0001, data);
  return data[0] * 0x100 + data[1];

}

float RS485_Wind_Direction_Transmitter_V2::GetWindAngle(uint8_t Adderss)
{
  uint8_t data[2] = {0};
  readHoldingRegister(0, 0x0000, data);
  return (data[0] * 0x100 + data[1]) / 10.0;

}

bool RS485_Wind_Direction_Transmitter_V2::SetSlaveAddress(uint8_t Address1, uint8_t Address2)
{
  return writeHoldingRegister(Address1, 0x1000, Address2);

}

uint8_t RS485_Wind_Direction_Transmitter_V2::GetSlaveAddress()
{
  uint8_t data[2] = {0};
  readHoldingRegister(0, 0x1000, data);
  return data[1];

}

size_t RS485_Wind_Direction_Transmitter_V2::readN(uint8_t *buf, size_t len)
{
  size_t offset = 0, left = len;
  int16_t Tineout = 1500;
  uint8_t  *buffer = buf;
  long curr = millis();
  bool val;

  while (left) {
    if(serialMode == 1){
      val = _softSerial->available();
    }else if(serialMode == 0){
      val = _hardSerial->available();
    }
  
    if (val) {

      if(serialMode == 1){
        buffer[offset] = _softSerial->read();
      }else if(serialMode == 0){
        buffer[offset] = _hardSerial->read();
      }
      
      offset++;
      left--;
    }
    if (millis() - curr > Tineout) {
      break;
    }
  }
  return offset;

}

uint16_t RS485_Wind_Direction_Transmitter_V2::CRC16_2(uint8_t *buf, int16_t len)
{
  uint16_t crc = 0xFFFF;
  for (int pos = 0; pos < len; pos++)
  {
    crc ^= (uint16_t)buf[pos];
    for (int i = 8; i != 0; i--)
    {
      if ((crc & 0x0001) != 0)
      {
        crc >>= 1;
        crc ^= 0xA001;
      }
      else
      {
        crc >>= 1;
      }
    }
  }

  crc = ((crc & 0x00ff) << 8) | ((crc & 0xff00) >> 8);
  return crc;  

}

void RS485_Wind_Direction_Transmitter_V2::addedCRC(uint8_t *buf, int len)
{
  uint16_t crc = 0xFFFF;
  for (int pos = 0; pos < len; pos++)
  {
    crc ^= (uint16_t)buf[pos];
    for (int i = 8; i != 0; i--)
    {
      if ((crc & 0x0001) != 0)
      {
        crc >>= 1;
        crc ^= 0xA001;
      }
      else
      {
        crc >>= 1;
      }
    }
  }
  buf[len] = crc % 0x100;
  buf[len + 1] = crc / 0x100;

}

bool RS485_Wind_Direction_Transmitter_V2::readHoldingRegister(uint8_t Address, uint16_t reg, uint8_t *data)
{
  uint8_t buf[7] = {0};       //用于储存传感器返回的原始数据包
  uint8_t COM[8] = {0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00};   //读取寄存器的指令
  long curr = millis();    //用于判断超时
  long curr1 = curr;       //用于判断超时
  uint8_t ch = 0;          //用于暂存串口数据
  COM[0] = Address;        //参考通讯协议将指令包添加完整。
  COM[2] = (reg / 0x100) % 0x100;
  COM[3] = reg % 0x100;

  addedCRC(COM , 6);   //为读取风向指令包添加CRC_16校验
  if(serialMode == 1){
    _softSerial->write(COM, 8);  //发送读取指令
  }else if(serialMode == 0){
    _hardSerial->write(COM, 8);  //发送读取指令
  }

  while (1) {
    if (millis() - curr > 1000) {
      return false;    //如果整个超过1000毫秒还未读取到正确的数据将视为超时，并返回—1.
    }

    if (millis() - curr1 > 100) {   //如果上一条读取风向的指令发出超过100毫秒还未收到返回指令将从新发送读取风向的指令
      if(serialMode == 1){
        _softSerial->write(COM, 8);  //发送读取指令
      }else if(serialMode == 0){
        _hardSerial->write(COM, 8);  //发送读取指令
      }
      curr1 = millis();
    }

    if (readN(&ch, 1) == 1) {
      if (ch == Address) {          //读取并判断包头。
        buf[0] = ch;
        if (readN(&ch, 1) == 1) {
          if (ch == 0x03) {         //读取并判断包头。
            buf[1] = ch;
            if (readN(&ch, 1) == 1) {
              if (ch == 0x02) {       //读取并判断包头。
                buf[2] = ch;
                if (readN(&buf[3], 4) == 4) {
                  //DBUG(buf, 8);
                  if (CRC16_2(buf, 5) == (buf[5] * 256 + buf[6])) {  //校验数据包
                    data[0] = buf[3];
                    data[1] = buf[4];
                    return true;
                  }
                }
              }
            }
          }
        }
      }
    }
  }    

}

bool RS485_Wind_Direction_Transmitter_V2::writeHoldingRegister(uint8_t Address, uint16_t reg, uint16_t parameter)
{
  uint8_t COM[11] = {0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00};  //写寄存器的命令
  uint8_t buf[8] = {0};   //用于储存传感器返回数据
  long curr = millis();   //用于判断超时
  long curr1 = curr;      //用于判断超时
  uint8_t ch = 0;         //用于暂存串口数据
  COM[0] = Address;                    //参考通讯协议将指令包添加完整。
  COM[2] = (reg / 0x100) % 0x100;
  COM[3] = reg % 0x100;
  COM[7] = (parameter / 0x100) % 0x100;
  COM[8] = parameter % 0x100;
  addedCRC(COM , 9);            //为指令包添加CRC_16校验

  if(serialMode == 1){
    _softSerial->write(COM, 11);  //发送读取风向的指令
  }else if(serialMode == 0){
    _hardSerial->write(COM, 11);  //发送读取风向的指令
  }

  while (1) {
    if (millis() - curr > 1000) {
      return false;
    }

    if (millis() - curr1 > 100) {
      if(serialMode == 1){
        _softSerial->write(COM, 11);  //发送读取风向的指令
      }else if(serialMode == 0){
        _hardSerial->write(COM, 11);  //发送读取风向的指令
      }
      curr1 = millis();
    }

    if (readN(&ch, 1) == 1) {
      if (ch == Address) {
        buf[0] = ch;
        if (readN(&ch, 1) == 1) {
          if (ch == 0x10) {
            buf[1] = ch;
            if (readN(&ch, 1) == 1) {
              if (ch == COM[2]) {
                buf[2] = ch;
                if (readN(&ch, 1) == 1) {
                  if (ch == COM[3]) {
                    buf[3] = ch;
                    if (readN(&buf[4], 4) == 4) {
                      if (CRC16_2(buf, 6) == (buf[6] * 256 + buf[7])) {  //校验数据包
                        //DBUG(buf, 8);
                        return true;
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}




